home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 9 / AMUG BBS in a Box Volume IX (August 1993) (MacWizards).iso / Files / Prog / U-Z / zmodem.source.cpt / rz.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-15  |  31.4 KB  |  1,493 lines

  1. #define VERSION "2.02 04-22-88"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*% cc -compat -M2 -Ox -K -i -DMD % -o rz; size rz;
  5. <-xtx-*> cc386 -Ox -DMD -DSEGMENTS=8 rz.c -o $B/rz;  size $B/rz
  6.  *
  7.  * rz.c By Chuck Forsberg
  8.  *
  9.  *    cc -O rz.c -o rz        USG (3.0) Unix
  10.  *     cc -O -DV7  rz.c -o rz        Unix V7, BSD 2.8 - 4.3
  11.  *
  12.  *    ln rz rb;  ln rz rx            For either system
  13.  *
  14.  *    ln rz /usr/bin/rzrmail        For remote mail.  Make this the
  15.  *                    login shell. rzrmail then calls
  16.  *                    rmail(1) to deliver mail.
  17.  *
  18.  * To compile on VMS:
  19.  *
  20.  *    define LNK$LIBRARY   SYS$LIBRARY:VAXCRTL.OLB
  21.  *    cc rz.c
  22.  *    cc vvmodem.c
  23.  *    link rz,vvmodem
  24.  *    rz :== $disk:[username.subdir]rz.exe
  25.  *
  26.  *
  27.  *  Unix is a trademark of Western Electric Company
  28.  *
  29.  * A program for Unix to receive files and commands from computers running
  30.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  31.  *  rz uses Unix buffered input to reduce wasted CPU time.
  32.  *
  33.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  34.  * "COMMAND filename"  (Unix only)
  35.  *
  36.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  37.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  38.  *  character reads for these systems. Added 7-01-84 CAF
  39.  *
  40.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  41.  *
  42.  *  BIX added 6-30-87 to support BIX(TM) upload protocol used by the
  43.  *  Byte Information Exchange.
  44.  *
  45.  *  NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
  46.  *  doesn't work properly (even though it compiles without error!),
  47.  *
  48.  *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
  49.  *    for CP/M-80 systems that cannot overlap modem and disk I/O.
  50.  *
  51.  *  VMS flavor hacks begin with rz version 2.00
  52.  *
  53.  *  -DMD may be added to compiler command line to compile in
  54.  *    Directory-creating routines from Public Domain TAR by John Gilmore
  55.  *
  56.  *  HOWMANY may be tuned for best performance
  57.  *
  58.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  59.  */
  60.  
  61. #ifdef vax11c
  62. #include <types.h>
  63. #include <stat.h>
  64. #define LOGFILE "rzlog.tmp"
  65. #include <stdio.h>
  66. #include <signal.h>
  67. #include <setjmp.h>
  68. #include <ctype.h>
  69. #include <errno.h>
  70. #define OS "VMS"
  71. #define BUFREAD
  72. extern int errno;
  73. #define SS_NORMAL SS$_NORMAL
  74. #else
  75. #define SS_NORMAL 0
  76. #define LOGFILE "/tmp/rzlog"
  77. #include <stdio.h>
  78. #include <signal.h>
  79. #include <setjmp.h>
  80. #include <ctype.h>
  81. #include <errno.h>
  82. extern int errno;
  83. FILE *popen();
  84. #endif
  85.  
  86. #define OK 0
  87. #define FALSE 0
  88. #define TRUE 1
  89. #define ERROR (-1)
  90.  
  91. /*
  92.  * Max value for HOWMANY is 255.
  93.  *   A larger value reduces system overhead but may evoke kernel bugs.
  94.  *   133 corresponds to an XMODEM/CRC sector
  95.  */
  96. #ifndef HOWMANY
  97. #define HOWMANY 133
  98. #endif
  99.  
  100. /* Ward Christensen / CP/M parameters - Don't change these! */
  101. #define ENQ 005
  102. #define CAN ('X'&037)
  103. #define XOFF ('s'&037)
  104. #define XON ('q'&037)
  105. #define SOH 1
  106. #define STX 2
  107. #define EOT 4
  108. #define ACK 6
  109. #define NAK 025
  110. #define CPMEOF 032
  111. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  112. #define TIMEOUT (-2)
  113. #define RCDO (-3)
  114. #define ERRORMAX 5
  115. #define RETRYMAX 5
  116. #define WCEOT (-10)
  117. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  118. #define UNIXFILE 0xF000    /* The S_IFMT file mask bit for stat */
  119.  
  120. int Zmodem=0;        /* ZMODEM protocol requested */
  121. int Nozmodem = 0;    /* If invoked as "rb" */
  122. unsigned Baudrate = 2400;
  123. #ifdef vax11c
  124. #include "vrzsz.c"    /* most of the system dependent stuff here */
  125. #else
  126. #include "rbsb.c"    /* most of the system dependent stuff here */
  127. #endif
  128. #include "crctab.c"
  129.  
  130. char *substr();
  131. FILE *fout;
  132.  
  133. /*
  134.  * Routine to calculate the free bytes on the current file system
  135.  *  ~0 means many free bytes (unknown)
  136.  */
  137. long getfree()
  138. {
  139.     return(~0L);    /* many free bytes ... */
  140. }
  141.  
  142. int Lastrx;
  143. int Crcflg;
  144. int Firstsec;
  145. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  146. int errors;
  147. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  148. #ifdef ONEREAD
  149. /* Sorry, Regulus and some others don't work right in raw mode! */
  150. int Readnum = 1;    /* Number of bytes to ask for in read() from modem */
  151. #else
  152. int Readnum = HOWMANY;    /* Number of bytes to ask for in read() from modem */
  153. #endif
  154.  
  155. #define DEFBYTL 2000000000L    /* default rx file size */
  156. long Bytesleft;        /* number of bytes of incoming file left */
  157. long Modtime;        /* Unix style mod time for incoming file */
  158. int Filemode;        /* Unix style mode for incoming file */
  159. char Pathname[PATHLEN];
  160. char *Progname;        /* the name by which we were called */
  161.  
  162. int Batch=0;
  163. int Topipe=0;
  164. int MakeLCPathname=TRUE;    /* make received pathname lower case */
  165. int Verbose=0;
  166. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  167. int Nflag = 0;        /* Don't really transfer files */
  168. int Rxclob=FALSE;    /* Clobber existing file */
  169. int Rxbinary=FALSE;    /* receive all files in bin mode */
  170. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  171. int Thisbinary;        /* current file is to be received in bin mode */
  172. int Blklen;        /* record length of received packets */
  173.  
  174. #ifdef SEGMENTS
  175. int chinseg = 0;    /* Number of characters received in this data seg */
  176. char secbuf[1+(SEGMENTS+1)*1024];
  177. #else
  178. char secbuf[1025];
  179. #endif
  180.  
  181.  
  182. char linbuf[HOWMANY];
  183. int Lleft=0;        /* number of characters in linbuf */
  184. time_t timep[2];
  185. char Lzmanag;        /* Local file management request */
  186. char zconv;        /* ZMODEM file conversion request */
  187. char zmanag;        /* ZMODEM file management request */
  188. char ztrans;        /* ZMODEM file transport request */
  189. int Zctlesc;        /* Encode control characters */
  190. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  191.  
  192. jmp_buf tohere;        /* For the interrupt on RX timeout */
  193.  
  194. #define xsendline(c) sendline(c)
  195. #include "zm.c"
  196.  
  197. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  198.  
  199. alrm()
  200. {
  201.     longjmp(tohere, -1);
  202. }
  203.  
  204. /* called by signal interrupt or terminate to clean things up */
  205. bibi(n)
  206. {
  207.     if (Zmodem)
  208.         zmputs(Attn);
  209.     canit(); mode(0);
  210.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  211.     cucheck();
  212.     exit(128+n);
  213. }
  214.  
  215. main(argc, argv)
  216. char *argv[];
  217. {
  218.     register char *cp;
  219.     register npats;
  220.     char *virgin, **patts;
  221.     char *getenv();
  222.     int exitcode;
  223.  
  224.     Rxtimeout = 100;
  225.     setbuf(stderr, NULL);
  226.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  227.         Restricted=TRUE;
  228.  
  229.     from_cu();
  230. #ifdef vax11c
  231.     Progname = virgin = "rz";
  232. #else
  233.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  234. #endif
  235.     npats = 0;
  236.     while (--argc) {
  237.         cp = *++argv;
  238.         if (*cp == '-') {
  239.             while( *++cp) {
  240.                 switch(*cp) {
  241.                 case '\\':
  242.                      cp[1] = toupper(cp[1]);  continue;
  243.                 case '+':
  244.                     Lzmanag = ZMAPND; break;
  245.                 case 'a':
  246.                     Rxascii=TRUE;  break;
  247.                 case 'b':
  248.                     Rxbinary=TRUE; break;
  249.                 case 'c':
  250.                     Crcflg=TRUE; break;
  251. #ifndef vax11c
  252.                 case 'D':
  253.                     Nflag = TRUE; break;
  254. #endif
  255.                 case 'e':
  256.                     Zctlesc = 1; break;
  257.                 case 'p':
  258.                     Lzmanag = ZMPROT;  break;
  259.                 case 'q':
  260.                     Quiet=TRUE; Verbose=0; break;
  261.                 case 't':
  262.                     if (--argc < 1) {
  263.                         usage();
  264.                     }
  265.                     Rxtimeout = atoi(*++argv);
  266.                     if (Rxtimeout<10 || Rxtimeout>1000)
  267.                         usage();
  268.                     break;
  269.                 case 'w':
  270.                     if (--argc < 1) {
  271.                         usage();
  272.                     }
  273.                     Zrwindow = atoi(*++argv);
  274.                     break;
  275.                 case 'u':
  276.                     MakeLCPathname=FALSE; break;
  277.                 case 'v':
  278.                     ++Verbose; break;
  279.                 case 'y':
  280.                     Rxclob=TRUE; break;
  281.                 default:
  282.                     usage();
  283.                 }
  284.             }
  285.         }
  286.         else if ( !npats && argc>0) {
  287.             if (argv[0][0]) {
  288.                 npats=argc;
  289.                 patts=argv;
  290.             }
  291.         }
  292.     }
  293.     if (npats > 1)
  294.         usage();
  295.     if (Batch && npats)
  296.         usage();
  297.     if (Verbose) {
  298.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  299.             printf("Can't open log file %s\n",LOGFILE);
  300.             exit(0200);
  301.         }
  302.         setbuf(stderr, NULL);
  303.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  304.     }
  305.     if (Fromcu && !Quiet) {
  306.         if (Verbose == 0)
  307.             Verbose = 2;
  308.     }
  309.     mode(1);
  310.     if (signal(SIGINT, bibi) == SIG_IGN) {
  311.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  312.     }
  313.     else {
  314.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  315.     }
  316.     signal(SIGTERM, bibi);
  317.     if (wcreceive(npats, patts)==ERROR) {
  318.         exitcode=0200;
  319.         canit();
  320.     }
  321.     mode(0);
  322.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  323.         canit();
  324.     if (exitcode)
  325.         cucheck();
  326.     exit(exitcode ? exitcode:SS_NORMAL);
  327. }
  328.  
  329.  
  330. usage()
  331. {
  332.     cucheck();
  333. #ifdef vax11c
  334.     fprintf(stderr,"Usage:    rz [-abeuvy]\n");
  335. #else
  336.     fprintf(stderr,"Usage:    rz [-abeuvy]        (ZMODEM)\n");
  337.     fprintf(stderr,"or    rb [-abuvy]        (YMODEM)\n");
  338.     fprintf(stderr,"or    rx [-abcv] file    (XMODEM or XMODEM-1k)\n");
  339. #endif
  340.     fprintf(stderr,"      -a ASCII transfer (strip CR)\n");
  341.     fprintf(stderr,"      -b Binary transfer for all files\n");
  342. #ifndef vax11c
  343.     fprintf(stderr,"      -c Use 16 bit CRC    (XMODEM)\n");
  344. #endif
  345.     fprintf(stderr,"      -e Escape control characters    (ZMODEM)\n");
  346.     fprintf(stderr,"      -v Verbose more v's give more info\n");
  347.     fprintf(stderr,"      -y Yes, clobber existing file if any\n");
  348.     fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
  349.       Progname, VERSION, OS);
  350.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
  351.     exit(SS_NORMAL);
  352. }
  353. /*
  354.  *  Debugging information output interface routine
  355.  */
  356. /* VARARGS1 */
  357. vfile(f, a, b, c)
  358. register char *f;
  359. {
  360.     if (Verbose > 2) {
  361.         fprintf(stderr, f, a, b, c);
  362.         fprintf(stderr, "\n");
  363.     }
  364. }
  365.  
  366. /*
  367.  * Let's receive something already.
  368.  */
  369.  
  370. char *rbmsg =
  371. "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n";
  372.  
  373. wcreceive(argc, argp)
  374. char **argp;
  375. {
  376.     register c;
  377.  
  378.     if (Batch || argc==0) {
  379.         Crcflg=1;
  380.         if ( !Quiet)
  381.             fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  382.         if (c=tryz()) {
  383.             if (c == ZCOMPL)
  384.                 return OK;
  385.             if (c == ERROR)
  386.                 goto fubar;
  387.             c = rzfiles();
  388.             if (c)
  389.                 goto fubar;
  390.         } else {
  391.             for (;;) {
  392.                 if (wcrxpn(secbuf)== ERROR)
  393.                     goto fubar;
  394.                 if (secbuf[0]==0)
  395.                     return OK;
  396.                 if (procheader(secbuf) == ERROR)
  397.                     goto fubar;
  398.                 if (wcrx()==ERROR)
  399.                     goto fubar;
  400.             }
  401.         }
  402.     } else {
  403.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  404.  
  405.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  406.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  407.         if ((fout=fopen(Pathname, "w")) == NULL)
  408.             return ERROR;
  409.         if (wcrx()==ERROR)
  410.             goto fubar;
  411.     }
  412.     return OK;
  413. fubar:
  414.     canit();
  415. #ifndef vax11c
  416.     if (Topipe && fout) {
  417.         pclose(fout);  return ERROR;
  418.     }
  419. #endif
  420.     if (fout)
  421.         fclose(fout);
  422. #ifndef vax11c
  423.     if (Restricted) {
  424.         unlink(Pathname);
  425.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  426.     }
  427. #endif
  428.     return ERROR;
  429. }
  430.  
  431.  
  432. /*
  433.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  434.  * Length is indeterminate as long as less than Blklen
  435.  * A null string represents no more files (YMODEM)
  436.  */
  437. wcrxpn(rpn)
  438. char *rpn;    /* receive a pathname */
  439. {
  440.     register c;
  441.  
  442. #ifdef NFGVMIN
  443.     readline(1);
  444. #else
  445.     purgeline();
  446. #endif
  447.  
  448. et_tu:
  449.     Firstsec=TRUE;  Eofseen=FALSE;
  450.     sendline(Crcflg?WANTCRC:NAK);
  451.     Lleft=0;    /* Do read next time ... */
  452.     while ((c = wcgetsec(rpn, 100)) != 0) {
  453.         if (c == WCEOT) {
  454.             zperr( "Pathname fetch returned %d", c);
  455.             sendline(ACK);
  456.             Lleft=0;    /* Do read next time ... */
  457.             readline(1);
  458.             goto et_tu;
  459.         }
  460.         return ERROR;
  461.     }
  462.     sendline(ACK);
  463.     return OK;
  464. }
  465.  
  466. /*
  467.  * Adapted from CMODEM13.C, written by
  468.  * Jack M. Wierda and Roderick W. Hart
  469.  */
  470.  
  471. wcrx()
  472. {
  473.     register int sectnum, sectcurr;
  474.     register char sendchar;
  475.     register char *p;
  476.     int cblklen;            /* bytes to dump this block */
  477.  
  478.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  479.     sendchar=Crcflg?WANTCRC:NAK;
  480.  
  481.     for (;;) {
  482.         sendline(sendchar);    /* send it now, we're ready! */
  483.         Lleft=0;    /* Do read next time ... */
  484.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  485.         report(sectcurr);
  486.         if (sectcurr==(sectnum+1 &0377)) {
  487.             sectnum++;
  488.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  489.             if (putsec(secbuf, cblklen)==ERROR)
  490.                 return ERROR;
  491.             if ((Bytesleft-=cblklen) < 0)
  492.                 Bytesleft = 0;
  493.             sendchar=ACK;
  494.         }
  495.         else if (sectcurr==(sectnum&0377)) {
  496.             zperr( "Received dup Sector");
  497.             sendchar=ACK;
  498.         }
  499.         else if (sectcurr==WCEOT) {
  500.             if (closeit())
  501.                 return ERROR;
  502.             sendline(ACK);
  503.             Lleft=0;    /* Do read next time ... */
  504.             return OK;
  505.         }
  506.         else if (sectcurr==ERROR)
  507.             return ERROR;
  508.         else {
  509.             zperr( "Sync Error");
  510.             return ERROR;
  511.         }
  512.     }
  513. }
  514.  
  515. /*
  516.  * Wcgetsec fetches a Ward Christensen type sector.
  517.  * Returns sector number encountered or ERROR if valid sector not received,
  518.  * or CAN CAN received
  519.  * or WCEOT if eot sector
  520.  * time is timeout for first char, set to 4 seconds thereafter
  521.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  522.  *    (Caller must do that when he is good and ready to get next sector)
  523.  */
  524.  
  525. wcgetsec(rxbuf, maxtime)
  526. char *rxbuf;
  527. int maxtime;
  528. {
  529.     register checksum, wcj, firstch;
  530.     register unsigned short oldcrc;
  531.     register char *p;
  532.     int sectcurr;
  533.  
  534.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  535.  
  536.         if ((firstch=readline(maxtime))==STX) {
  537.             Blklen=1024; goto get2;
  538.         }
  539.         if (firstch==SOH) {
  540.             Blklen=128;
  541. get2:
  542.             sectcurr=readline(1);
  543.             if ((sectcurr+(oldcrc=readline(1)))==0377) {
  544.                 oldcrc=checksum=0;
  545.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  546.                     if ((firstch=readline(1)) < 0)
  547.                         goto bilge;
  548.                     oldcrc=updcrc(firstch, oldcrc);
  549.                     checksum += (*p++ = firstch);
  550.                 }
  551.                 if ((firstch=readline(1)) < 0)
  552.                     goto bilge;
  553.                 if (Crcflg) {
  554.                     oldcrc=updcrc(firstch, oldcrc);
  555.                     if ((firstch=readline(1)) < 0)
  556.                         goto bilge;
  557.                     oldcrc=updcrc(firstch, oldcrc);
  558.                     if (oldcrc & 0xFFFF)
  559.                         zperr( "CRC");
  560.                     else {
  561.                         Firstsec=FALSE;
  562.                         return sectcurr;
  563.                     }
  564.                 }
  565.                 else if (((checksum-firstch)&0377)==0) {
  566.                     Firstsec=FALSE;
  567.                     return sectcurr;
  568.                 }
  569.                 else
  570.                     zperr( "Checksum");
  571.             }
  572.             else
  573.                 zperr("Sector number garbled");
  574.         }
  575.         /* make sure eot really is eot and not just mixmash */
  576. #ifdef NFGVMIN
  577.         else if (firstch==EOT && readline(1)==TIMEOUT)
  578.             return WCEOT;
  579. #else
  580.         else if (firstch==EOT && Lleft==0)
  581.             return WCEOT;
  582. #endif
  583.         else if (firstch==CAN) {
  584.             if (Lastrx==CAN) {
  585.                 zperr( "Sender CANcelled");
  586.                 return ERROR;
  587.             } else {
  588.                 Lastrx=CAN;
  589.                 continue;
  590.             }
  591.         }
  592.         else if (firstch==TIMEOUT) {
  593.             if (Firstsec)
  594.                 goto humbug;
  595. bilge:
  596.             zperr( "TIMEOUT");
  597.         }
  598.         else
  599.             zperr( "Got 0%o sector header", firstch);
  600.  
  601. humbug:
  602.         Lastrx=0;
  603.         while(readline(1)!=TIMEOUT)
  604.             ;
  605.         if (Firstsec) {
  606.             sendline(Crcflg?WANTCRC:NAK);
  607.             Lleft=0;    /* Do read next time ... */
  608.         } else {
  609.             maxtime=40; sendline(NAK);
  610.             Lleft=0;    /* Do read next time ... */
  611.         }
  612.     }
  613.     /* try to stop the bubble machine. */
  614.     canit();
  615.     return ERROR;
  616. }
  617.  
  618. #ifndef vax11c
  619. /*
  620.  * This version of readline is reasoably well suited for
  621.  * reading many characters.
  622.  *  (except, currently, for the Regulus version!)
  623.  *
  624.  * timeout is in tenths of seconds
  625.  */
  626. readline(timeout)
  627. int timeout;
  628. {
  629.     register n;
  630.     static char *cdq;    /* pointer for removing chars from linbuf */
  631.  
  632.     if (--Lleft >= 0) {
  633.         if (Verbose > 8) {
  634.             fprintf(stderr, "%02x ", *cdq&0377);
  635.         }
  636.         return (*cdq++ & 0377);
  637.     }
  638.     n = timeout/10;
  639.     if (n < 2)
  640.         n = 3;
  641.     if (Verbose > 5)
  642.         fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
  643.           n, Readnum);
  644.     if (setjmp(tohere)) {
  645. #ifdef TIOCFLUSH
  646. /*        ioctl(iofd, TIOCFLUSH, 0); */
  647. #endif
  648.         Lleft = 0;
  649.         if (Verbose>1)
  650.             fprintf(stderr, "Readline:TIMEOUT\n");
  651.         return TIMEOUT;
  652.     }
  653.     signal(SIGALRM, alrm); alarm(n);
  654.     Lleft=read(iofd, cdq=linbuf, Readnum);
  655.     alarm(0);
  656.     if (Verbose > 5) {
  657.         fprintf(stderr, "Read returned %d bytes\n", Lleft);
  658.     }
  659.     if (Lleft < 1)
  660.         return TIMEOUT;
  661.     --Lleft;
  662.     if (Verbose > 8) {
  663.         fprintf(stderr, "%02x ", *cdq&0377);
  664.     }
  665.     return (*cdq++ & 0377);
  666. }
  667.  
  668.  
  669.  
  670. /*
  671.  * Purge the modem input queue of all characters
  672.  */
  673. purgeline()
  674. {
  675.     Lleft = 0;
  676. #ifdef USG
  677.     ioctl(iofd, TCFLSH, 0);
  678. #else
  679.     lseek(iofd, 0L, 2);
  680. #endif
  681. }
  682. #endif
  683.  
  684.  
  685. /*
  686.  * Process incoming file information header
  687.  */
  688. procheader(name)
  689. char *name;
  690. {
  691.     register char *openmode, *p, **pp;
  692.  
  693.     /* set default parameters and overrides */
  694.     openmode = "w";
  695.     Thisbinary = (!Rxascii) || Rxbinary;
  696.     if (Lzmanag)
  697.         zmanag = Lzmanag;
  698.  
  699.     /*
  700.      *  Process ZMODEM remote file management requests
  701.      */
  702.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  703.         Thisbinary = 0;
  704.     if (zconv == ZCBIN)    /* Remote Binary override */
  705.         Thisbinary = TRUE;
  706.     else if (zmanag == ZMAPND)
  707.         openmode = "a";
  708.  
  709. #ifndef BIX
  710.     /* Check for existing file */
  711.     if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) {
  712.         fclose(fout);  return ERROR;
  713.     }
  714. #endif
  715.  
  716.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  717.  
  718.     p = name + 1 + strlen(name);
  719.     if (*p) {    /* file coming from Unix or DOS system */
  720.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  721. #ifndef vax11c
  722.         if (Filemode & UNIXFILE)
  723.             ++Thisbinary;
  724. #endif
  725.         if (Verbose) {
  726.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  727.               name, Bytesleft, Modtime, Filemode);
  728.         }
  729.     }
  730.  
  731. #ifdef BIX
  732.     if ((fout=fopen("scratchpad", openmode)) == NULL)
  733.         return ERROR;
  734.     return OK;
  735. #else
  736.  
  737.     else {        /* File coming from CP/M system */
  738.         for (p=name; *p; ++p)        /* change / to _ */
  739.             if ( *p == '/')
  740.                 *p = '_';
  741.  
  742.         if ( *--p == '.')        /* zap trailing period */
  743.             *p = 0;
  744.     }
  745.  
  746. #ifndef vax11c
  747.     if (!Zmodem && MakeLCPathname && !IsAnyLower(name)
  748.       && !(Filemode&UNIXFILE))
  749.         uncaps(name);
  750. #endif
  751.     if (Topipe) {
  752.         sprintf(Pathname, "%s %s", Progname+2, name);
  753.         if (Verbose)
  754.             fprintf(stderr,  "Topipe: %s %s\n",
  755.               Pathname, Thisbinary?"BIN":"ASCII");
  756. #ifndef vax11c
  757.         if ((fout=popen(Pathname, "w")) == NULL)
  758.             return ERROR;
  759. #endif
  760.     } else {
  761.         strcpy(Pathname, name);
  762.         if (Verbose) {
  763.             fprintf(stderr,  "Receiving %s %s %s\n",
  764.               name, Thisbinary?"BIN":"ASCII", openmode);
  765.         }
  766.         checkpath(name);
  767.         if (Nflag)
  768.             name = "/dev/null";
  769. #ifdef MD
  770.         fout = fopen(name, openmode);
  771.         if ( !fout)
  772.             if (make_dirs(name))
  773.                 fout = fopen(name, openmode);
  774. #else
  775.         fout = fopen(name, openmode);
  776. #endif
  777.         if ( !fout)
  778.             return ERROR;
  779.     }
  780.     return OK;
  781. #endif /* BIX */
  782. }
  783.  
  784. #ifdef MD
  785. /*
  786.  *  Directory-creating routines from Public Domain TAR by John Gilmore
  787.  */
  788.  
  789. /*
  790.  * After a file/link/symlink/dir creation has failed, see if
  791.  * it's because some required directory was not present, and if
  792.  * so, create all required dirs.
  793.  */
  794. make_dirs(pathname)
  795. register char *pathname;
  796. {
  797.     register char *p;        /* Points into path */
  798.     int madeone = 0;        /* Did we do anything yet? */
  799.     int save_errno = errno;        /* Remember caller's errno */
  800.     char *strchr();
  801.  
  802.     if (errno != ENOENT)
  803.         return 0;        /* Not our problem */
  804.  
  805.     for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
  806.         /* Avoid mkdir of empty string, if leading or double '/' */
  807.         if (p == pathname || p[-1] == '/')
  808.             continue;
  809.         /* Avoid mkdir where last part of path is '.' */
  810.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  811.             continue;
  812.         *p = 0;                /* Truncate the path there */
  813.         if ( !mkdir(pathname, 0777)) {    /* Try to create it as a dir */
  814.             vfile("Made directory %s\n", pathname);
  815.             madeone++;        /* Remember if we made one */
  816.             *p = '/';
  817.             continue;
  818.         }
  819.         *p = '/';
  820.         if (errno == EEXIST)        /* Directory already exists */
  821.             continue;
  822.         /*
  823.          * Some other error in the mkdir.  We return to the caller.
  824.          */
  825.         break;
  826.     }
  827.     errno = save_errno;        /* Restore caller's errno */
  828.     return madeone;            /* Tell them to retry if we made one */
  829. }
  830.  
  831. #if (MD != 2)
  832. #define    TERM_SIGNAL(status)    ((status) & 0x7F)
  833. #define TERM_COREDUMP(status)    (((status) & 0x80) != 0)
  834. #define TERM_VALUE(status)    ((status) >> 8)
  835. /*
  836.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  837.  */
  838. mkdir(dpath, dmode)
  839. char *dpath;
  840. int dmode;
  841. {
  842.     int cpid, status;
  843.     struct stat statbuf;
  844.  
  845.     if (stat(dpath,&statbuf) == 0) {
  846.         errno = EEXIST;        /* Stat worked, so it already exists */
  847.         return -1;
  848.     }
  849.  
  850.     /* If stat fails for a reason other than non-existence, return error */
  851.     if (errno != ENOENT) return -1; 
  852.  
  853.     switch (cpid = fork()) {
  854.  
  855.     case -1:            /* Error in fork() */
  856.         return(-1);        /* Errno is set already */
  857.  
  858.     case 0:                /* Child process */
  859.         /*
  860.          * Cheap hack to set mode of new directory.  Since this
  861.          * child process is going away anyway, we zap its umask.
  862.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  863.          * directory.  Does anybody care?
  864.          */
  865.         status = umask(0);    /* Get current umask */
  866.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  867.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  868.         _exit(-1);        /* Can't exec /bin/mkdir */
  869.     
  870.     default:            /* Parent process */
  871.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  872.     }
  873.  
  874.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  875.         errno = EIO;        /* We don't know why, but */
  876.         return -1;        /* /bin/mkdir failed */
  877.     }
  878.  
  879.     return 0;
  880. }
  881. #endif /* MD != 2 */
  882. #endif /* MD */
  883.  
  884. /*
  885.  * Putsec writes the n characters of buf to receive file fout.
  886.  *  If not in binary mode, carriage returns, and all characters
  887.  *  starting with CPMEOF are discarded.
  888.  */
  889. putsec(buf, n)
  890. char *buf;
  891. register n;
  892. {
  893.     register char *p;
  894.  
  895.     if (n == 0)
  896.         return OK;
  897.     if (Thisbinary) {
  898.         for (p=buf; --n>=0; )
  899.             putc( *p++, fout);
  900.     }
  901.     else {
  902.         if (Eofseen)
  903.             return OK;
  904.         for (p=buf; --n>=0; ++p ) {
  905.             if ( *p == '\r')
  906.                 continue;
  907.             if (*p == CPMEOF) {
  908.                 Eofseen=TRUE; return OK;
  909.             }
  910.             putc(*p ,fout);
  911.         }
  912.     }
  913.     return OK;
  914. }
  915.  
  916. #ifndef vax11c
  917. /*
  918.  *  Send a character to modem.  Small is beautiful.
  919.  */
  920. sendline(c)
  921. {
  922.     char d;
  923.  
  924.     d = c;
  925.     if (Verbose>6)
  926.         fprintf(stderr, "Sendline: %x\n", c);
  927.     write(1, &d, 1);
  928. }
  929.  
  930. flushmo() {}
  931. #endif
  932.  
  933.  
  934.  
  935.  
  936.  
  937. /* make string s lower case */
  938. uncaps(s)
  939. register char *s;
  940. {
  941.     for ( ; *s; ++s)
  942.         if (isupper(*s))
  943.             *s = tolower(*s);
  944. }
  945. /*
  946.  * IsAnyLower returns TRUE if string s has lower case letters.
  947.  */
  948. IsAnyLower(s)
  949. register char *s;
  950. {
  951.     for ( ; *s; ++s)
  952.         if (islower(*s))
  953.             return TRUE;
  954.     return FALSE;
  955. }
  956.  
  957. /*
  958.  * substr(string, token) searches for token in string s
  959.  * returns pointer to token within string if found, NULL otherwise
  960.  */
  961. char *
  962. substr(s, t)
  963. register char *s,*t;
  964. {
  965.     register char *ss,*tt;
  966.     /* search for first char of token */
  967.     for (ss=s; *s; s++)
  968.         if (*s == *t)
  969.             /* compare token with substring */
  970.             for (ss=s,tt=t; ;) {
  971.                 if (*tt == 0)
  972.                     return s;
  973.                 if (*ss++ != *tt++)
  974.                     break;
  975.             }
  976.     return NULL;
  977. }
  978.  
  979. /*
  980.  * Log an error
  981.  */
  982. /*VARARGS1*/
  983. zperr(s,p,u)
  984. char *s, *p, *u;
  985. {
  986.     if (Verbose <= 0)
  987.         return;
  988.     fprintf(stderr, "Retry %d: ", errors);
  989.     fprintf(stderr, s, p, u);
  990.     fprintf(stderr, "\n");
  991. }
  992.  
  993. /* send cancel string to get the other end to shut up */
  994. canit()
  995. {
  996.     static char canistr[] = {
  997.      24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  998.     };
  999.  
  1000. #ifdef vax11c
  1001.     raw_wbuf(strlen(canistr), canistr);
  1002.     purgeline();
  1003. #else
  1004.     printf(canistr);
  1005.     Lleft=0;    /* Do read next time ... */
  1006.     fflush(stdout);
  1007. #endif
  1008. }
  1009.  
  1010.  
  1011. report(sct)
  1012. int sct;
  1013. {
  1014.     if (Verbose>1)
  1015.         fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
  1016. }
  1017.  
  1018. #ifndef vax11c
  1019. /*
  1020.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  1021.  * If called as [-][dir/../]rzCOMMAND set the pipe flag
  1022.  * If called as rb use YMODEM protocol
  1023.  */
  1024. chkinvok(s)
  1025. char *s;
  1026. {
  1027.     register char *p;
  1028.  
  1029.     p = s;
  1030.     while (*p == '-')
  1031.         s = ++p;
  1032.     while (*p)
  1033.         if (*p++ == '/')
  1034.             s = p;
  1035.     if (*s == 'v') {
  1036.         Verbose=1; ++s;
  1037.     }
  1038.     Progname = s;
  1039.     if (s[0]=='r' && s[1]=='z')
  1040.         Batch = TRUE;
  1041.     if (s[0]=='r' && s[1]=='b')
  1042.         Batch = Nozmodem = TRUE;
  1043.     if (s[2] && s[0]=='r' && s[1]=='b')
  1044.         Topipe=TRUE;
  1045.     if (s[2] && s[0]=='r' && s[1]=='z')
  1046.         Topipe=TRUE;
  1047. }
  1048. #endif
  1049.  
  1050. /*
  1051.  * Totalitarian Communist pathname processing
  1052.  */
  1053. checkpath(name)
  1054. char *name;
  1055. {
  1056.     if (Restricted) {
  1057.         if (fopen(name, "r") != NULL) {
  1058.             canit();
  1059.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  1060.             bibi(-1);
  1061.         }
  1062.         /* restrict pathnames to current tree or uucppublic */
  1063.         if ( substr(name, "../")
  1064.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  1065.             canit();
  1066.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  1067.             bibi(-1);
  1068.         }
  1069.     }
  1070. }
  1071.  
  1072. /*
  1073.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  1074.  *  Handles ZSINIT frame
  1075.  *  Return ZFILE if Zmodem filename received, -1 on error,
  1076.  *   ZCOMPL if transaction finished,  else 0
  1077.  */
  1078. tryz()
  1079. {
  1080.     register c, n;
  1081.     register cmdzack1flg;
  1082.  
  1083.     if (Nozmodem)        /* Check for "rb" program name */
  1084.         return 0;
  1085.  
  1086.  
  1087.     for (n=Zmodem?15:5; --n>=0; ) {
  1088.         /* Set buffer length (0) and capability flags */
  1089. #ifdef SEGMENTS
  1090.         stohdr(SEGMENTS*1024L);
  1091. #else
  1092.         stohdr(0L);
  1093. #endif
  1094. #ifdef CANBREAK
  1095.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  1096. #else
  1097.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  1098. #endif
  1099.         if (Zctlesc)
  1100.             Txhdr[ZF0] |= TESCCTL;
  1101.         zshhdr(tryzhdrtype, Txhdr);
  1102.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  1103.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  1104. again:
  1105.         switch (zgethdr(Rxhdr, 0)) {
  1106.         case ZRQINIT:
  1107.             continue;
  1108.         case ZEOF:
  1109.             continue;
  1110.         case TIMEOUT:
  1111.             continue;
  1112.         case ZFILE:
  1113.             zconv = Rxhdr[ZF0];
  1114.             zmanag = Rxhdr[ZF1];
  1115.             ztrans = Rxhdr[ZF2];
  1116.             tryzhdrtype = ZRINIT;
  1117.             c = zrdata(secbuf, 1024);
  1118.             mode(3);
  1119.             if (c == GOTCRCW)
  1120.                 return ZFILE;
  1121.             zshhdr(ZNAK, Txhdr);
  1122.             goto again;
  1123.         case ZSINIT:
  1124.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  1125.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  1126.                 stohdr(1L);
  1127.                 zshhdr(ZACK, Txhdr);
  1128.                 goto again;
  1129.             }
  1130.             zshhdr(ZNAK, Txhdr);
  1131.             goto again;
  1132.         case ZFREECNT:
  1133.             stohdr(getfree());
  1134.             zshhdr(ZACK, Txhdr);
  1135.             goto again;
  1136.         case ZCOMMAND:
  1137. #ifdef vax11c
  1138.             return ERROR;
  1139. #else
  1140.             cmdzack1flg = Rxhdr[ZF0];
  1141.             if (zrdata(secbuf, 1024) == GOTCRCW) {
  1142.                 if (cmdzack1flg & ZCACK1)
  1143.                     stohdr(0L);
  1144.                 else
  1145.                     stohdr((long)sys2(secbuf));
  1146.                 purgeline();    /* dump impatient questions */
  1147.                 do {
  1148.                     zshhdr(ZCOMPL, Txhdr);
  1149.                 }
  1150.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  1151.                 ackbibi();
  1152.                 if (cmdzack1flg & ZCACK1)
  1153.                     exec2(secbuf);
  1154.                 return ZCOMPL;
  1155.             }
  1156.             zshhdr(ZNAK, Txhdr); goto again;
  1157. #endif
  1158.         case ZCOMPL:
  1159.             goto again;
  1160.         default:
  1161.             continue;
  1162.         case ZFIN:
  1163.             ackbibi(); return ZCOMPL;
  1164.         case ZCAN:
  1165.             return ERROR;
  1166.         }
  1167.     }
  1168.     return 0;
  1169. }
  1170.  
  1171. /*
  1172.  * Receive 1 or more files with ZMODEM protocol
  1173.  */
  1174. rzfiles()
  1175. {
  1176.     register c;
  1177.  
  1178.     for (;;) {
  1179.         switch (c = rzfile()) {
  1180.         case ZEOF:
  1181.         case ZSKIP:
  1182.             switch (tryz()) {
  1183.             case ZCOMPL:
  1184.                 return OK;
  1185.             default:
  1186.                 return ERROR;
  1187.             case ZFILE:
  1188.                 break;
  1189.             }
  1190.             continue;
  1191.         default:
  1192.             return c;
  1193.         case ERROR:
  1194.             return ERROR;
  1195.         }
  1196.     }
  1197. }
  1198.  
  1199. /*
  1200.  * Receive a file with ZMODEM protocol
  1201.  *  Assumes file name frame is in secbuf
  1202.  */
  1203. rzfile()
  1204. {
  1205.     register c, n;
  1206.     long rxbytes;
  1207.  
  1208.     Eofseen=FALSE;
  1209.     if (procheader(secbuf) == ERROR) {
  1210.         return (tryzhdrtype = ZSKIP);
  1211.     }
  1212.  
  1213.     n = 20; rxbytes = 0l;
  1214.  
  1215.     for (;;) {
  1216. #ifdef SEGMENTS
  1217.         chinseg = 0;
  1218. #endif
  1219.         stohdr(rxbytes);
  1220.         zshhdr(ZRPOS, Txhdr);
  1221. nxthdr:
  1222.         switch (c = zgethdr(Rxhdr, 0)) {
  1223.         default:
  1224.             vfile("rzfile: zgethdr returned %d", c);
  1225.             return ERROR;
  1226.         case ZNAK:
  1227.         case TIMEOUT:
  1228. #ifdef SEGMENTS
  1229.             putsec(secbuf, chinseg);
  1230.             chinseg = 0;
  1231. #endif
  1232.             if ( --n < 0) {
  1233.                 vfile("rzfile: zgethdr returned %d", c);
  1234.                 return ERROR;
  1235.             }
  1236.         case ZFILE:
  1237.             zrdata(secbuf, 1024);
  1238.             continue;
  1239.         case ZEOF:
  1240. #ifdef SEGMENTS
  1241.             putsec(secbuf, chinseg);
  1242.             chinseg = 0;
  1243. #endif
  1244.             if (rclhdr(Rxhdr) != rxbytes) {
  1245.                 /*
  1246.                  * Ignore eof if it's at wrong place - force
  1247.                  *  a timeout because the eof might have gone
  1248.                  *  out before we sent our zrpos.
  1249.                  */
  1250.                 errors = 0;  goto nxthdr;
  1251.             }
  1252.             if (closeit()) {
  1253.                 tryzhdrtype = ZFERR;
  1254.                 vfile("rzfile: closeit returned <> 0");
  1255.                 return ERROR;
  1256.             }
  1257.             vfile("rzfile: normal EOF");
  1258.             return c;
  1259.         case ERROR:    /* Too much garbage in header search error */
  1260. #ifdef SEGMENTS
  1261.             putsec(secbuf, chinseg);
  1262.             chinseg = 0;
  1263. #endif
  1264.             if ( --n < 0) {
  1265.                 vfile("rzfile: zgethdr returned %d", c);
  1266.                 return ERROR;
  1267.             }
  1268.             zmputs(Attn);
  1269.             continue;
  1270.         case ZSKIP:
  1271. #ifdef SEGMENTS
  1272.             putsec(secbuf, chinseg);
  1273.             chinseg = 0;
  1274. #endif
  1275.             closeit();
  1276.             vfile("rzfile: Sender SKIPPED file");
  1277.             return c;
  1278.         case ZDATA:
  1279.             if (rclhdr(Rxhdr) != rxbytes) {
  1280.                 if ( --n < 0) {
  1281.                     return ERROR;
  1282.                 }
  1283. #ifdef SEGMENTS
  1284.                 putsec(secbuf, chinseg);
  1285.                 chinseg = 0;
  1286. #endif
  1287.                 zmputs(Attn);  continue;
  1288.             }
  1289. moredata:
  1290.             if (Verbose>1)
  1291.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1292.                   rxbytes, Crc32?" CRC-32":"");
  1293. #ifdef SEGMENTS
  1294.             if (chinseg >= (1024 * SEGMENTS)) {
  1295.                 putsec(secbuf, chinseg);
  1296.                 chinseg = 0;
  1297.             }
  1298.             switch (c = zrdata(secbuf+chinseg, 1024))
  1299. #else
  1300.             switch (c = zrdata(secbuf, 1024))
  1301. #endif
  1302.             {
  1303.             case ZCAN:
  1304. #ifdef SEGMENTS
  1305.                 putsec(secbuf, chinseg);
  1306.                 chinseg = 0;
  1307. #endif
  1308.                 vfile("rzfile: zgethdr returned %d", c);
  1309.                 return ERROR;
  1310.             case ERROR:    /* CRC error */
  1311. #ifdef SEGMENTS
  1312.                 putsec(secbuf, chinseg);
  1313.                 chinseg = 0;
  1314. #endif
  1315.                 if ( --n < 0) {
  1316.                     vfile("rzfile: zgethdr returned %d", c);
  1317.                     return ERROR;
  1318.                 }
  1319.                 zmputs(Attn);
  1320.                 continue;
  1321.             case TIMEOUT:
  1322. #ifdef SEGMENTS
  1323.                 putsec(secbuf, chinseg);
  1324.                 chinseg = 0;
  1325. #endif
  1326.                 if ( --n < 0) {
  1327.                     vfile("rzfile: zgethdr returned %d", c);
  1328.                     return ERROR;
  1329.                 }
  1330.                 continue;
  1331.             case GOTCRCW:
  1332.                 n = 20;
  1333. #ifdef SEGMENTS
  1334.                 chinseg += Rxcount;
  1335.                 putsec(secbuf, chinseg);
  1336.                 chinseg = 0;
  1337. #else
  1338.                 putsec(secbuf, Rxcount);
  1339. #endif
  1340.                 rxbytes += Rxcount;
  1341.                 stohdr(rxbytes);
  1342.                 zshhdr(ZACK, Txhdr);
  1343.                 sendline(XON);
  1344.                 goto nxthdr;
  1345.             case GOTCRCQ:
  1346.                 n = 20;
  1347. #ifdef SEGMENTS
  1348.                 chinseg += Rxcount;
  1349. #else
  1350.                 putsec(secbuf, Rxcount);
  1351. #endif
  1352.                 rxbytes += Rxcount;
  1353.                 stohdr(rxbytes);
  1354.                 zshhdr(ZACK, Txhdr);
  1355.                 goto moredata;
  1356.             case GOTCRCG:
  1357.                 n = 20;
  1358. #ifdef SEGMENTS
  1359.                 chinseg += Rxcount;
  1360. #else
  1361.                 putsec(secbuf, Rxcount);
  1362. #endif
  1363.                 rxbytes += Rxcount;
  1364.                 goto moredata;
  1365.             case GOTCRCE:
  1366.                 n = 20;
  1367. #ifdef SEGMENTS
  1368.                 chinseg += Rxcount;
  1369. #else
  1370.                 putsec(secbuf, Rxcount);
  1371. #endif
  1372.                 rxbytes += Rxcount;
  1373.                 goto nxthdr;
  1374.             }
  1375.         }
  1376.     }
  1377. }
  1378.  
  1379. /*
  1380.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  1381.  *   and \335 (break signal)
  1382.  */
  1383. zmputs(s)
  1384. char *s;
  1385. {
  1386.     register c;
  1387.  
  1388.     while (*s) {
  1389.         switch (c = *s++) {
  1390.         case '\336':
  1391.             sleep(1); continue;
  1392.         case '\335':
  1393.             sendbrk(); continue;
  1394.         default:
  1395.             sendline(c);
  1396.         }
  1397.     }
  1398. }
  1399.  
  1400. /*
  1401.  * Close the receive dataset, return OK or ERROR
  1402.  */
  1403. closeit()
  1404. {
  1405.     time_t time();
  1406.  
  1407. #ifndef vax11c
  1408.     if (Topipe) {
  1409.         if (pclose(fout)) {
  1410.             return ERROR;
  1411.         }
  1412.         return OK;
  1413.     }
  1414. #endif
  1415.     if (fclose(fout)==ERROR) {
  1416.         fprintf(stderr, "file close ERROR\n");
  1417.         return ERROR;
  1418.     }
  1419. #ifndef vax11c
  1420.     if (Modtime) {
  1421.         timep[0] = time(NULL);
  1422.         timep[1] = Modtime;
  1423.         utime(Pathname, timep);
  1424.     }
  1425. #endif
  1426.     if ((Filemode&S_IFMT) == S_IFREG)
  1427.         chmod(Pathname, (07777 & Filemode));
  1428.     return OK;
  1429. }
  1430.  
  1431. /*
  1432.  * Ack a ZFIN packet, let byegones be byegones
  1433.  */
  1434. ackbibi()
  1435. {
  1436.     register n;
  1437.  
  1438.     vfile("ackbibi:");
  1439.     Readnum = 1;
  1440.     stohdr(0L);
  1441.     for (n=3; --n>=0; ) {
  1442.         purgeline();
  1443.         zshhdr(ZFIN, Txhdr);
  1444.         switch (readline(100)) {
  1445.         case 'O':
  1446.             readline(1);    /* Discard 2nd 'O' */
  1447.             vfile("ackbibi complete");
  1448.             return;
  1449.         case RCDO:
  1450.             return;
  1451.         case TIMEOUT:
  1452.         default:
  1453.             break;
  1454.         }
  1455.     }
  1456. }
  1457.  
  1458.  
  1459.  
  1460. /*
  1461.  * Local console output simulation
  1462.  */
  1463. bttyout(c)
  1464. {
  1465.     if (Verbose || Fromcu)
  1466.         putc(c, stderr);
  1467. }
  1468.  
  1469. #ifndef vax11c
  1470. /*
  1471.  * Strip leading ! if present, do shell escape. 
  1472.  */
  1473. sys2(s)
  1474. register char *s;
  1475. {
  1476.     if (*s == '!')
  1477.         ++s;
  1478.     return system(s);
  1479. }
  1480. /*
  1481.  * Strip leading ! if present, do exec.
  1482.  */
  1483. exec2(s)
  1484. register char *s;
  1485. {
  1486.     if (*s == '!')
  1487.         ++s;
  1488.     mode(0);
  1489.     execl("/bin/sh", "sh", "-c", s);
  1490. }
  1491. #endif
  1492. /* End of rz.c */
  1493.